using IQIGame.Onigao.Framework;
using System;

namespace IQIGame.Onigao.Logic
{
    public class SkillTrigger : IReusableClass
    {
        protected Skill skill;
        protected virtual ESkillTriggerType triggerType => ESkillTriggerType.Min;
        private int listenerID;

        private int priority;
        public long triggerPart;

        public bool enable { get; private set; }
        public SkillCondition triggerCondiditon { get; private set; }

        protected Unit executer => this.skill.executer;
        public bool hasCondition => this.triggerCondiditon != null;

        public void Initialize(Skill rSkill, TriggerConfig rConfig)
        {
            this.skill = rSkill;
            this.priority = rConfig.priority;
            this.triggerPart = rConfig.triggerPart;

            var rCondConfig = rConfig.condition;
            if (rCondConfig != null)
            {
                var rCond = ClassPool.Get<SkillCondition>();
                rCond.Initialize(rSkill, rCondConfig);
                rCond.CheckFormula = rConfig.condition.formulaID;
                this.triggerCondiditon = rCond;
            }

            this.OnInitialize(rSkill, rConfig);
        }

        public void Enable()
        {
            if (!this.enable)
            {
                this.enable = true;
                this.OnEnable();
            }
        }

        public void Disable()
        {
            if (this.enable)
            {
                this.enable = false;
                if (this.listenerID > 0)
                {
                    this.executer.battle.playCtrl.triggerCtrl.RemoveListener(this.listenerID);
                }
                this.listenerID = 0;
                this.OnDisable();
            }
        }

        public void Dispose()
        {
            this.Disable();
        }

        public SkillPart GetTriggerPart(object param)
        {
            if (this.triggerCondiditon == null)
            {
                this.skill.partsDict.TryGetValue(this.triggerPart, out var rPart);
                return rPart;
            }

            return this.triggerCondiditon.GetExecute(param);
        }

        protected void AddListener(EBattleTriggerType eventType, Action handler)
        {
            if (this.listenerID == 0)
            {
                this.listenerID = this.executer.battle.playCtrl.triggerCtrl.AddListener(eventType, this.priority, handler);
            }
        }

        protected void AddListener<T>(EBattleTriggerType eventType, Action<T> handler)
        {
            if (this.listenerID == 0)
            {
                this.listenerID = this.executer.battle.playCtrl.triggerCtrl.AddListener(eventType, this.priority, handler);
            }
        }

        protected void AddListener<T1, T2>(EBattleTriggerType eventType, Action<T1, T2> handler)
        {
            if (this.listenerID == 0)
            {
                this.listenerID = this.executer.battle.playCtrl.triggerCtrl.AddListener(eventType, this.priority, handler);
            }
        }

        protected void AddListener<T1, T2, T3>(EBattleTriggerType eventType, Action<T1, T2, T3> handler)
        {
            if (this.listenerID == 0)
            {
                this.listenerID = this.executer.battle.playCtrl.triggerCtrl.AddListener(eventType, this.priority, handler);
            }
        }
        
        protected void AddListener<T1, T2, T3, T4>(EBattleTriggerType eventType, Action<T1, T2, T3, T4> handler)
        {
            if (this.listenerID == 0)
            {
                this.listenerID = this.executer.battle.playCtrl.triggerCtrl.AddListener(eventType, this.priority, handler);
            }
        }
        

        protected virtual void OnInitialize(Skill rSkill, TriggerConfig rConfig)
        {
        }

        protected virtual void OnEnable()
        {
        }

        protected virtual void OnDisable()
        {
        }

        protected void OnTrigger(SelectParam rVirtualInput, object param = null)
        {
            this.skill.Trigger(this, rVirtualInput, param);
        }

        public uint MaxStore => 3;

        public virtual void OnReset()
        {
            this.skill = null;
            this.triggerPart = 0;
            this.priority = 0;
            if (this.triggerCondiditon != null)
            {
                ClassPool.Put(this.triggerCondiditon);
                this.triggerCondiditon = null;
            }
        }

        public virtual void Free()
        {
            ClassPool.Put(this);
        }

#if UNITY_EDITOR
        public override string ToString()
        {
            return this.GetType().ToString();
        }
#endif
    }

    // 值不可修改，已序列化
    public enum ESkillTriggerType
    {
        Min,
        SelfAttacked,
        SelfAttackOther,
        SelfBattleStart,
        SelfAddBuff,
        SelfCustomProperty,

        AddBuff,
        ExecuteSkill,
        SkillDamageTempModify,
        Attacked,
        RoundEnd,
        CustomProperty,
        StartBattle,
        StartRound,
        UnitDie,

        Max,
    }
}